package com.dingreading.cloud.ssxcx.util;

import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.dingreading.cloud.common.base.R;
import com.dingreading.cloud.common.dto.MstOssStsDto;
import com.dingreading.cloud.common.util.MstXcxClassType;
import com.dingreading.cloud.common.util.aliyun.MstCdnUtil;
import com.dingreading.cloud.common.util.aliyun.MstOSSClientUtil;
import com.dingreading.cloud.common.util.aliyun.OSSClientUtil;
import com.dingreading.cloud.ssxcx.dto.*;
import com.dingreading.cloud.ssxcx.entity.SubjectLesson;
import com.dingreading.cloud.ssxcx.entity.Subjects;
import com.dingreading.cloud.ssxcx.entity.XcxHomeworkFilesTrack;
import com.dingreading.cloud.ssxcx.entity.XcxLessonMaterials;
import com.dingreading.cloud.ssxcx.service.*;
import com.dingreading.cloud.ssxcx.util.redis.RedisService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Component
public class DataProcessUtils {
    public static final String KEY_PROJECT_UID = "projectUid";
    public static final String KEY_STAGE_UID = "stageUid";
    public static final String KEY_QUESTION_UID = "questionUid";
    private static final String xcxXbyDirHomework = "xcxXbyData/homework/";
    /**
     * 名师堂cdn加速域名
     */
    @Value("${aliYun.cdn.mstCdnDomain}")
    private String mstCdnDomain;
    @Value("${aliYun.cdn.mstPrivateKey}")
    private String mstPrivateKey;

    @Resource
    private RedisService redisService;
    @Resource
    private SubjectsService subjectsService;
    @Resource
    private MembersService membersService;
    @Resource
    private SubjectLessonService subjectLessonService;
    @Resource
    private XcxMaterialsFilesService xcxMaterialsFilesService;
    @Resource
    private XcxLessonMaterialsService xcxLessonMaterialsService;
    @Resource
    private XcxHomeworkFilesTrackService xcxHomeworkFileTrackService;

    // 辅助类：用于封装查询到的课节和科目数据
    private static class LessonSubjectMaps {
        private final Map<String, SubjectLesson> lessonMap;
        private final Map<Long, String> subjectNameMap;

        public LessonSubjectMaps(Map<String, SubjectLesson> lessonMap, Map<Long, String> subjectNameMap) {
            this.lessonMap = lessonMap;
            this.subjectNameMap = subjectNameMap;
        }

        public Map<String, SubjectLesson> getLessonMap() {
            return lessonMap;
        }

        public Map<Long, String> getSubjectNameMap() {
            return subjectNameMap;
        }
    }

    public R<Object> checkStudentUid(String agencyUid, String studentUid) {
        MembersDto membersDto = membersService.getByUid(studentUid);
        if (membersDto == null) {
            return R.fail("用户不存在");
        }
        if (!membersDto.getEnabled().equals(1)) {
            return R.fail("账号已被禁用");
        }
        return R.ok(membersDto);
    }

    public Map<String, String> getLessonMaterialUids(String subjectLessonUid, Integer materialStage) {
        XcxLessonMaterials lessonMaterials = xcxLessonMaterialsService.getLatest(subjectLessonUid, materialStage);

        String projectUid = null;
        String stageUid = null;
        String uid = null;

        if (lessonMaterials != null) {
            projectUid = lessonMaterials.getProjectUid();
            stageUid = lessonMaterials.getStageUid();
            uid = lessonMaterials.getUid();
        }

        Map<String, String> result = new HashMap<>();
        result.put(KEY_PROJECT_UID, projectUid);
        result.put(KEY_STAGE_UID, stageUid);
        result.put(KEY_QUESTION_UID, uid);

        return result;
    }

    public void dealQuizAnswers(List<XcxStudentQuizAnswersDto> records, String ip) {
        // 1. 收集所有不重复的 questionUids，用于查询图片文件
        List<String> uniqueQuestionUids = records.stream()
                .map(XcxStudentQuizAnswersDto::getQuestionUid).filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList());

        // 2. 收集所有不重复的 subjectLessonUids，用于查询课节信息
        List<String> uniqueLessonUids = records.stream()
                .map(XcxStudentQuizAnswersDto::getSubjectLessonUid).filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList());

        // 3. 调用提取的方法处理图片文件
        Map<String, List<String>> imageFilesMap = processQuestionImageUrls(uniqueQuestionUids, ip);

        // 调用可重用方法获取课节和科目数据
        LessonSubjectMaps lessonSubjectMaps = fetchLessonAndSubjectMaps(uniqueLessonUids);
        Map<String, SubjectLesson> lessonMap = lessonSubjectMaps.getLessonMap();
        Map<Long, String> subjectNameMap = lessonSubjectMaps.getSubjectNameMap();

        // 收集所有不重复的 URL
        Map<String, String> processedUrlMap = new HashMap<>();
        List<XcxLearningOptionsDto> xcxLearningOptionsDtos = records.stream().map(XcxStudentQuizAnswersDto::getXcxOptions).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(xcxLearningOptionsDtos)) {
            List<String> orginUrls = xcxLearningOptionsDtos.stream()
                    .map(xcxOption -> {
                        if (xcxOption != null && StringUtils.isNotBlank(xcxOption.getUrl())) {
                            return xcxOption.getUrl();
                        } else {
                            return "";
                        }
                    })
                    .filter(StringUtils::isNotBlank)
                    .distinct().collect(Collectors.toList());

            long expire = MstCdnUtil.getImgExpire();
            // 处理所有唯一的 URL 并存储结果
            processedUrlMap = orginUrls.stream()
                    .collect(Collectors.toMap(
                            url -> url,
                            url -> getXcxUrl(url, ip, expire)
                    ));
        }

        // 7. 遍历 records，填充 imageUrls 和 titles
        for (XcxStudentQuizAnswersDto dto : records) {
            // 从已经处理过 CDN 的 imageFilesMap 中获取图片URL列表
            dto.setQuestionImageUrls(imageFilesMap.getOrDefault(dto.getQuestionUid(), Collections.emptyList()));
            XcxLearningOptionsDto quizOptions = dto.getXcxOptions();
            if (quizOptions != null) {
                String quizOptionUrl = quizOptions.getUrl();
                if (StringUtils.isNotBlank(quizOptionUrl)) {
                    String cdnUrl = processedUrlMap.get(quizOptionUrl);
                    if (StringUtils.isNotBlank(cdnUrl)) {
                        quizOptions.setCdnUrl(cdnUrl);
                    }
                }
            }
            SubjectLesson lesson = lessonMap.get(dto.getSubjectLessonUid());
            if (lesson != null) {
                dto.setTitles(buildLessonTitles(lesson, subjectNameMap));
                dto.setLessonName(lesson.getLessonName() + "-" + MstXcxClassType.INCLASS.getName());
            }
        }
    }

    public void dealHomework(List<XcxStudentHomeworkDto> records, String ip) {
        // 1. 收集所有不重复的 subjectLessonUids
        List<String> uniqueLessonUids = records.stream()
                .map(XcxStudentHomeworkDto::getSubjectLessonUid)
                .filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList());

        List<String> uniqueQuestionUids = records.stream()
                .map(XcxStudentHomeworkDto::getQuestionUid).filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList());

        Map<String, List<String>> imageFilesMap = processQuestionImageUrls(uniqueQuestionUids, ip);

        // 调用可重用方法获取课节和科目数据
        LessonSubjectMaps lessonSubjectMaps = fetchLessonAndSubjectMaps(uniqueLessonUids);
        Map<String, SubjectLesson> lessonMap = lessonSubjectMaps.getLessonMap();
        Map<Long, String> subjectNameMap = lessonSubjectMaps.getSubjectNameMap();

        // 遍历 records，填充 Homework DTO 的相关字段
        for (XcxStudentHomeworkDto dto : records) {
            // 从已经处理过 CDN 的 imageFilesMap 中获取图片URL列表
            dto.setQuestionImageUrls(imageFilesMap.getOrDefault(dto.getQuestionUid(), Collections.emptyList()));
            SubjectLesson lesson = lessonMap.get(dto.getSubjectLessonUid());
            if (lesson != null) {
                dto.setTitles(buildLessonTitles(lesson, subjectNameMap));
                dto.setLessonName(lesson.getLessonName() + "-" + MstXcxClassType.AFTERCLASS.getName());
            }
            if (dto != null && CollectionUtils.isNotEmpty(dto.getHomeworkImageUrls())) {
                long expire = MstCdnUtil.getImgExpire();
                List<String> cdnImageUrls = dto.getHomeworkImageUrls().stream()
                        .map((String url) -> getXcxUrl(url, ip, expire))
                        .collect(Collectors.toList());
                dto.setHomeworkImageUrls(cdnImageUrls);
            }
        }
    }

    public void dealLearningProgress(List<XcxStudentLearningProgressDto> records, String ip) {

        // 1. 收集所有不重复的 questionUids，用于查询图片文件
        List<String> uniqueQuestionUids = records.stream()
                .map(XcxStudentLearningProgressDto::getQuestionUid).filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList());

        // 2. 收集所有不重复的 subjectLessonUids
        List<String> uniqueLessonUids = records.stream()
                .map(XcxStudentLearningProgressDto::getSubjectLessonUid)
                .filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList());

        // 3. 处理图片文件
        Map<String, List<String>> imageFilesMap = processQuestionImageUrls(uniqueQuestionUids, ip);

        // 调用可重用方法获取课节和科目数据
        LessonSubjectMaps lessonSubjectMaps = fetchLessonAndSubjectMaps(uniqueLessonUids);
        Map<String, SubjectLesson> lessonMap = lessonSubjectMaps.getLessonMap();
        Map<Long, String> subjectNameMap = lessonSubjectMaps.getSubjectNameMap();

        // 收集所有不重复的 URL
        Map<String, String> processedUrlMap = new HashMap<>();
        List<XcxLearningOptionsDto> xcxLearningOptionsDtos = records.stream().map(XcxStudentLearningProgressDto::getQuizOptions).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(xcxLearningOptionsDtos)) {
            List<String> orginUrls = xcxLearningOptionsDtos.stream()
                    .map(xcxOption -> {
                        if (xcxOption != null && StringUtils.isNotBlank(xcxOption.getUrl())) {
                            return xcxOption.getUrl();
                        } else {
                            return "";
                        }
                    })
                    .filter(StringUtils::isNotBlank)
                    .distinct().collect(Collectors.toList());

            long expire = MstCdnUtil.getImgExpire();
            // 处理所有唯一的 URL 并存储结果
            processedUrlMap = orginUrls.stream()
                    .collect(Collectors.toMap(
                            url -> url,
                            url -> getXcxUrl(url, ip, expire)
                    ));
        }

        // 遍历 records，填充 LearningProgress DTO 的相关字段
        for (XcxStudentLearningProgressDto dto : records) {
            SubjectLesson lesson = lessonMap.get(dto.getSubjectLessonUid());
            dto.setQuestionImageUrls(imageFilesMap.getOrDefault(dto.getQuestionUid(), Collections.emptyList()));
            if (lesson != null) {
                dto.setTitles(buildLessonTitles(lesson, subjectNameMap));
                dto.setLessonName(lesson.getLessonName() + "-" + MstXcxClassType.getName(dto.getMaterialStage()));
            }

            XcxLearningOptionsDto quizOptions = dto.getQuizOptions();
            if (quizOptions != null) {
                String quizOptionUrl = quizOptions.getUrl();
                if (StringUtils.isNotBlank(quizOptionUrl)) {
                    String cdnUrl = processedUrlMap.get(quizOptionUrl);
                    if (StringUtils.isNotBlank(cdnUrl)) {
                        quizOptions.setCdnUrl(cdnUrl);
                    }
                }
            }

            if (dto != null && CollectionUtils.isNotEmpty(dto.getHomeworkImageUrls())) {
                long expire = MstCdnUtil.getImgExpire();
                List<String> cdnImageUrls = dto.getHomeworkImageUrls().stream()
                        .map((String url) -> getXcxUrl(url, ip, expire))
                        .collect(Collectors.toList());
                dto.setHomeworkImageUrls(cdnImageUrls);
            }
        }
    }

    /**
     * 可重用的私有方法：根据课节UID集合获取课节和科目名称的Map
     *
     * @param uniqueLessonUids 不重复的课节UID集合
     * @return 包含课节信息和科目名称信息的辅助对象
     */
    private LessonSubjectMaps fetchLessonAndSubjectMaps(List<String> uniqueLessonUids) {
        Map<String, SubjectLesson> lessonMap = new HashMap<>();
        Map<Long, String> subjectNameMap = new HashMap<>();

        if (CollectionUtils.isNotEmpty(uniqueLessonUids)) {
            // 4. 根据 uniqueLessonUids 获取 SubjectLesson 信息
            List<SubjectLesson> subjectLessons = subjectLessonService.getByLessonUids(uniqueLessonUids);
            if (CollectionUtils.isNotEmpty(subjectLessons)) {
                lessonMap = subjectLessons.stream()
                        .collect(Collectors.toMap(SubjectLesson::getUid, Function.identity()));
            }

            // 5. 收集所有不重复的 subjectNodes 中的 subjectId
            Set<Long> uniqueSubjectIds = new HashSet<>();
            for (SubjectLesson lesson : lessonMap.values()) {
                String nodesStr = lesson.getSubjectNodes(); // 格式如 ",7,11,13,"
                if (StringUtils.isNotBlank(nodesStr)) {
                    // 移除开头和结尾的逗号，然后按逗号分割
                    String[] ids = nodesStr.replaceAll("^,+|,+$", "").split(",");
                    for (String idStr : ids) {
                        if (StringUtils.isNotBlank(idStr)) {
                            try {
                                uniqueSubjectIds.add(Long.parseLong(idStr.trim()));
                            } catch (NumberFormatException e) {
                                // 实际项目中应使用日志框架记录错误
                                System.err.println("解析 subjectNodes 中的ID失败: " + idStr + ", 原始字符串: " + nodesStr);
                            }
                        }
                    }
                }
            }

            // 6. 根据 uniqueSubjectIds 获取 Subjects 名称
            if (CollectionUtils.isNotEmpty(uniqueSubjectIds)) {
                List<Subjects> subjectsList = subjectsService.getBySubjectIds(uniqueSubjectIds);
                if (CollectionUtils.isNotEmpty(subjectsList)) {
                    subjectNameMap = subjectsList.stream()
                            .collect(Collectors.toMap(Subjects::getId, Subjects::getSubjectName));
                }
            }
        }
        return new LessonSubjectMaps(lessonMap, subjectNameMap);
    }

    /**
     * 构建基于科目节点和（可选的）课节名称的标题列表。
     * 这个方法封装了从 SubjectLesson 中解析 subjectNodes 并查找科目名称的逻辑。
     *
     * @param lesson         The SubjectLesson 对象，包含课节信息。
     * @param subjectNameMap 科目ID到科目名称的映射。
     * @return 标题字符串列表。
     */
    private List<String> buildLessonTitles(SubjectLesson lesson, Map<Long, String> subjectNameMap) {
        List<String> titles = new ArrayList<>();
        if (lesson != null) {
            String nodesStr = lesson.getSubjectNodes();
            if (StringUtils.isNotBlank(nodesStr)) {
                String[] ids = nodesStr.replaceAll("^,+|,+$", "").split(",");
                int count = 0;
                for (String idStr : ids) {
                    if (StringUtils.isNotBlank(idStr) && count < 3) { // 限制最多3层
                        try {
                            Long subjectId = Long.parseLong(idStr.trim());
                            String subjectName = subjectNameMap.get(subjectId);
                            if (StringUtils.isNotBlank(subjectName)) {
                                titles.add(subjectName);
                                count++;
                            }
                        } catch (NumberFormatException e) {
                            // 实际项目中应使用日志框架记录错误
                            System.err.println("解析 subjectNodes 中的ID失败（构建titles时）: " + idStr + ", 原始字符串: " + nodesStr);
                        }
                    }
                }
            }
        }
        return titles;
    }

    /**
     * 提取的私有方法：处理问题（题目）相关的图片文件，转换为 CDN URL 映射。
     *
     * @param questionUids 唯一的题目UID列表。
     * @param ip
     * @return 题目UID到其 CDN 图片URL列表的映射。
     */
    private Map<String, List<String>> processQuestionImageUrls(List<String> questionUids, String ip) {
        Map<String, List<String>> imageFilesMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(questionUids)) {
            Map<String, List<String>> rawImageFilesMap = xcxMaterialsFilesService.listByOptionUidsMap(questionUids);

            long expire = MstCdnUtil.getImgExpire();
            rawImageFilesMap.forEach((questionUid, urls) -> {
                if (CollectionUtils.isNotEmpty(urls)) {
                    List<String> cdnUrls = urls.stream()
                            .map((String url) -> getXcxUrl(url, ip, expire))
                            .collect(Collectors.toList());
                    imageFilesMap.put(questionUid, cdnUrls);
                } else {
                    imageFilesMap.put(questionUid, Collections.emptyList());
                }
            });
        }
        return imageFilesMap;
    }

    // CDN URL 转换方法
    public String getXcxUrl(String url, String ip, long expire) {
        if (StringUtils.isBlank(url)) {
            return "";
        }
//        String urlAuthA = MstCdnUtil.getUrlAuthA(url);
//        return ossDomain + url + urlAuthA;

        return MstCdnUtil.getXcxCdnUrl(mstCdnDomain, mstPrivateKey, url, ip, expire);
    }

    /**
     * 获取阿里云的临时授权信息
     */
    public R<Object> getOssSts(String fileType) {
        MstOSSClientUtil ossClientUtil = new MstOSSClientUtil();
        String todayDir = ossClientUtil.getTodaySplitDir(xcxXbyDirHomework);
        if (StringUtils.isBlank(todayDir))
            return R.fail("获取阿里云上传路径失败");

        String fileName = ossClientUtil.getCourseVideoFileName(fileType);
        if (StringUtils.isBlank(fileName))
            return R.fail("生成文件名失败");
        String finalName = todayDir.concat(fileName);

        String securityToken = (String) redisService.get(MstOSSClientUtil.STS_SECURITYTOKEN);
        String accessKeyId = (String) redisService.get(MstOSSClientUtil.STS_ACCESSKEYID);
        String accessKeySecret = (String) redisService.get(MstOSSClientUtil.STS_ACCESSKEYSECRET);
        String expiration = (String) redisService.get(MstOSSClientUtil.STS_EXPIRATION);
        if (StringUtils.isBlank(securityToken) || StringUtils.isBlank(accessKeyId) || StringUtils.isBlank(accessKeySecret) || StringUtils.isBlank(expiration)) {
            AssumeRoleResponse.Credentials response = ossClientUtil.getAssumeRoleResponse();
            if (response == null)
                return R.fail("获取阿里云STS授权失败");

            securityToken = response.getSecurityToken();
            accessKeyId = response.getAccessKeyId();
            accessKeySecret = response.getAccessKeySecret();
            expiration = response.getExpiration();

            redisService.set(MstOSSClientUtil.STS_SECURITYTOKEN, securityToken, 1800);
            redisService.set(MstOSSClientUtil.STS_ACCESSKEYID, accessKeyId, 1800);
            redisService.set(MstOSSClientUtil.STS_ACCESSKEYSECRET, accessKeySecret, 1800);
            redisService.set(MstOSSClientUtil.STS_EXPIRATION, expiration, 1800);
        }
        String region = MstOSSClientUtil.region;
        String privateBucket = MstOSSClientUtil.privateBucket_subject;

        MstOssStsDto dto = new MstOssStsDto();
        dto.setAccessKeyId(accessKeyId);
        dto.setAccessKeySecret(accessKeySecret);
        dto.setSecurityToken(securityToken);
        dto.setRegion(region);
        dto.setBucket(privateBucket);
        dto.setFileName(finalName);
        dto.setExpiration(expiration);

        XcxHomeworkFilesTrack newFilesTrack = XcxEntityUtils.newFilesTrack(finalName);
        if (newFilesTrack != null) {
            xcxHomeworkFileTrackService.save(newFilesTrack);
        }

        return R.ok(dto);
    }

}
